#ifndef _Thread_H_
#define _Thread_H_

#include <map>
#include <string>
#include <pthread.h>
#include <netdb.h>
#include "Socket.hpp"
//线程
class Thread {
private:				
    pthread_t _tid;//线程标识
public:
	//析构函数
	virtual ~Thread (void) {}
	void start () //启动线程
    {
        // 线程属性结构
        pthread_attr_t attr;
        // 初始化线程属性结构
        pthread_attr_init(&attr);
        // 设置线程栈空间大小：1M字节
        pthread_attr_setstacksize(&attr, 1024 * 1024);
        // 设置线程分离状态：创建即分离
        pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);

        // 创建线程。线程标识存入成员变量m_tid，线程属性取自先前设
        // 置好的线程属性结构attr，线程过程函数为静态成员函数run，
        // 传递给线程过程函数的参数为指向线程(子类)对象的this指针
        int error = pthread_create(&_tid, &attr, run, this);
        // 若失败
        if (error)
        {   // 记录一般错误日志
            // g_app->m_log.printf(Log::LEVEL_ERR, __FILE__, __LINE__,
            //                     "pthread_create: %s", strerror(error));
		}
        // 销毁线程属性结构
        pthread_attr_destroy(&attr);
    }

private:
	/// @brief 线程过程函数
	/// @return 线程返回值
	///< [in,out] 线程参数
	static void* run (void* arg)
    {
        // 通过指向子类对象的基类指针，即创建线程时交给系统内核并由系
        // 统内核回传给线程过程函数的参数arg，调用在线程抽象基类中声
        // 明并为其具体子类所覆盖的虚函数run，执行具体线程的具体任务
        return static_cast<Thread*>(arg)->run();
    }
	virtual void* run () = 0;//纯虚函数，子类根据不同线程的具体任务给出具体实现
};

//接受线程
class RecvThread : public Thread {
	Socket* _socket;//套接字
public:
	//构造函数
	RecvThread (Socket* socket):_socket(socket) {}
	//析构函数
	~RecvThread () {delete _socket;}
private:
	
	//根据接收线程的任务实现基类中的纯虚函数
	void* run () //线程处理函数
	{
		// 记录调试日志
		// g_app->m_log.printf(Log::LEVEL_DBG, __FILE__, __LINE__,
		// 					"接收线程开始");

		// 通过套接字接收超文本传输协议响
		// 应，根据其执行情况停止抓取任务
		g_app->stopJob(_socket->recvResponse());
		// 对象自毁
		delete this;
		// 记录调试日志
		// g_app->m_log.printf(Log::LEVEL_DBG, __FILE__, __LINE__,
		// 					"接收线程终止");
		// 终止线程
		return NULL;
	}
};

//发送线程
// @brief 发送线程
class SendThread : public Thread {
private:
	//根据发送线程的任务实现基类中的纯虚函数
	void* run () //线程处理函数
	{
		// 记录调试日志
		// g_app->m_log.printf(Log::LEVEL_DBG, __FILE__, __LINE__,
		// 					"发送线程开始");

		// 无限循环
		for (;;)
			// 启动一个抓取任务
			g_app->startJob();

		// 记录调试日志
		// g_app->m_log.printf(Log::LEVEL_DBG, __FILE__, __LINE__,
		// 					"接收线程终止");
		// 终止线程
		return NULL;
	}
};


//域名解析线程
class DnsThread : public Thread {
private:
	//根据域名解析线程的任务实现基类中的纯虚函数
	//线程处理函数
	std::map<std::string, std::string> DnsThread::s_hosts;
    void* run ()
	{
		// 记录调试日志
		// g_app->m_log.printf (Log::LEVEL_DBG, __FILE__, __LINE__,
		// 	"DNS线程开始");

		// 无限循环
		for (;;)
		{
			// 从统一资源定位符队列，弹出原始统一资源
			// 定位符，并显式转换为解析统一资源定位符
			DnsUrl dnsUrl = static_cast<DnsUrl>(g_app->_urlQueues.popRawUrl());

			// 在主机域名————IP地址映射表中，
			// 查找该统一资源定位符的主机域名
			std::map<std::string, std::string>::const_iterator it =
				s_hosts.find(dnsUrl._domain);

			// 若找到了
			if (it != s_hosts.end())
			{
				// 将与该主机域名对应的IP地址，
				// 存入解析统一资源定位符
				dnsUrl._ip = it->second;
				// 将解析统一资源定位符，压入统一资源定位符队列
				g_app->_urlQueues.pushDnsUrl(dnsUrl);

				// 记录调试日志
				// g_app->m_log.printf (Log::LEVEL_DBG, __FILE__, __LINE__,
				// 	"域名\"%s\"曾经被解析为\"%s\"", dnsUrl.m_domain.c_str (),
				// 	dnsUrl.m_ip.c_str ());
				// 继续下一轮循环
				continue;
			}

			// 若没找到，则通过域名系统获取与该主机域名对应的IP地址
			hostent *host = gethostbyname(dnsUrl._domain.c_str());

			// 若失败
			if (!host)
			{
				// 记录警告日志
				// g_app->_log.printf(Log::LEVEL_WAR, __FILE__, __LINE__,
				// 					"gethostbyname: %s", hstrerror(h_errno));
				// 继续下一轮循环
				continue;
			}

			//     hostent
			// +-------------+
			// | h_name      -> xxx\0          - 正式主机名
			// | h_aliases   -> * * * ... NULL - 别名表
			// | h_addrtype  |  AF_INET        - 地址类型
			// | h_length    |  4              - 地址字节数
			// | h_addr_list -> * * * ... NULL - 地址表
			// +-------------+  +-> in_addr    - IPv4地址结构

			// 若地址类型不是IPv4
			if (host->h_addrtype != AF_INET)
			{
				// 记录警告日志
				// g_app->m_log.printf(Log::LEVEL_WAR, __FILE__, __LINE__,
				// 					"无效地址类型");
				// 继续下一轮循环
				continue;
			}

			// 将IPv4地址结构转换为点分十进制字符串，存入解析统
			// 一资源定位符，同时加入主机域名————IP地址映射表
			s_hosts[dnsUrl._domain] = dnsUrl._ip = inet_ntoa(**(in_addr **)host->h_addr_list);
			// 将解析统一资源定位符，压入统一资源定位符队列
			g_app->_urlQueues.pushDnsUrl(dnsUrl);

			// 记录调试日志
			// g_app->m_log.printf (Log::LEVEL_DBG, __FILE__, __LINE__,
			// 	"域名\"%s\"被成功解析为\"%s\"", dnsUrl.m_domain.c_str (),
			// 	dnsUrl.m_ip.c_str ());
			/*
			// 初始化libevent库
			event_base* base = event_init ();
			// 初始化dns模块
			evdns_init ();

			// 一旦完成对该主机域名的解析即调用回调函数
			evdns_resolve_ipv4 (dnsUrl.m_domain.c_str (), 0,
				callback, &dnsUrl);
			// 进入事件循环
			event_dispatch ();

			// 释放libevent库
			event_base_free (base);
			*/
		}

		// 记录调试日志
		// g_app->m_log.printf (Log::LEVEL_DBG, __FILE__, __LINE__,
		// 	"DNS线程终止");
		// 终止线程
		return nullptr;
	}
};


#endif //_Thread_H_